package cn.johnnyjian.getris.game

import groovy.mock.interceptor.MockFor
import static org.junit.Assert.*
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized)
class QuadrelTest {

	static quadrel
	def squares
	def offset

	@Parameters static data() {
		[
			[
				[
					[0, 1, 0],
					[1, 1, 1]
				],
				[left: 1, top: 1]
			],
			[
				[
					[1, 0],
					[1, 1],
					[1, 0]
				],
				[left: 1, top: 1]
			],
			[
				[
					[1, 1, 1],
					[0, 1, 0]
				],
				[left: 0, top: 1]
			],
			[
				[
					[0, 1],
					[1, 1],
					[0, 1]
				],
				[left: 1, top: 0]
			]
		].collect { it as Object[] }
	}

	QuadrelTest(a, b) {
		squares = a as boolean[][]
		offset = b
	}

	@BeforeClass static void createQuadrel() {
		quadrel = new MockQuadrel()
	}

	@Test void testRotate() {
		assertArrayEquals squares, quadrel.rotate().squares
		assertEquals offset, quadrel.offset
	}

}

class OtherQuadrelTest {

	static quadrel

	@BeforeClass static void createQuadrel() {
		quadrel = new MockQuadrel()
	}

	private testCopyOrRemove(expected, name) {
		final points = [[3, 2], [2, 3], [3, 3], [3, 4]] as Set

		def mockContainer = new MockFor(Container)
		mockContainer.demand.setSquareAt(4..4) {x, y, square ->
			assertTrue([x, y] in points)
			assertEquals expected, square
			points.remove([x, y])
		}
		def container = new Container(10, 20, 1)
		mockContainer.use(container) {
			quadrel."$name"(container, 1, 2)
		}
	}

	@Test void testCopyTo() {
		testCopyOrRemove(true, 'copyTo')
	}

	@Test void testRemoveFrom() {
		testCopyOrRemove(false, 'removeFrom')
	}

	@Test void testIsSquareAt() {
		assertTrue quadrel.isSquareAt(2, 0)
		assertFalse quadrel.isSquareAt(1, 0)
		assertTrue quadrel.isSquareAt(1, 1)
		assertFalse quadrel.isSquareAt(1, 2)

		assertFalse quadrel.isSquareAt(0, 0)
		assertFalse quadrel.isSquareAt(2, 3)
		assertFalse quadrel.isSquareAt(-1, -1)
		assertFalse quadrel.isSquareAt(4, 4)
	}

	@Test void testEachSquare() {
		def points = [
		    [2, 0], [1, 1], [2, 1], [2, 2]
		]
		def i = 0
		quadrel.eachSquare { x, y ->
			assertSame quadrel, delegate
			assertEquals points[i++], [x, y]
		}
	}

	@Test void testGetWidth() {
		assertEquals 2, quadrel.width
	}

	@Test void testGetHeight() {
		assertEquals 3, quadrel.height
	}

	@Test void testGetLeft() {
		assertEquals 1, quadrel.left
	}

	@Test void testGetRight() {
		assertEquals 2, quadrel.right
	}

	@Test void testGetTop() {
		assertEquals 0, quadrel.top
	}

	@Test void testGetBottom() {
		assertEquals 2, quadrel.bottom
	}

}

class MockQuadrel extends Quadrel {

	def squares = [
		[0, 1],
		[1, 1],
		[0, 1]
	] as boolean[][]
	def bound = 4
	def offset = [left: 1, top: 0]

}
